﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Device_Finder_MVC4.Models;
using System.Security.Cryptography;
using System.Text;

namespace Device_Finder_MVC4.DAL
{
    public class UserDAL : BaseDAL
    {
        public bool ChangeUserInfo(USER info, string oldPass)
        {
            string encryptPass = Encrypt(oldPass, info.EMAIL, true);
            var lstUser = from u in entities.USERs
                          where info.EMAIL == u.EMAIL && encryptPass == u.PASSWORD
                          select u;

            if (lstUser != null && lstUser.Count() > 0)
            {
                // Set information for each field of User's table
                USER user = lstUser.First();
                user.PASSWORD = Encrypt(info.PASSWORD, info.EMAIL, true);
                entities.SaveChanges();

                return true;
            }

            return false;
        }

        public bool ExistEmail(string email)
        {
            var lstUser = from u in entities.USERs
                          where u.EMAIL == email
                          select u;

            return (lstUser != null && lstUser.Count() > 0) ? true : false;
        }

        public bool Validate(string email, string password)
        {
            string encryptPass = Encrypt(password, email, true);

            var lstUser = from u in entities.USERs
                          where u.EMAIL == email && u.PASSWORD == encryptPass
                          select u;

            return (lstUser != null && lstUser.Count() > 0) ? true : false;
        }

        public CreateUserStatus CreateUser(string email, string password)
        {
            CreateUserStatus ret = CreateUserStatus.Success;
            if (ExistEmail(email))
            {
                ret |= CreateUserStatus.DuplicateEmail;
            }
            if (!ValidEmailSyntax(email))
            {
                ret |= CreateUserStatus.EmailInvalid;
            }
            if (ret != CreateUserStatus.Success)
                return ret;

            USER user = new USER();
            user.EMAIL = email;
            user.PASSWORD = Encrypt(password, email, true);

            this.entities.USERs.Add(user);
            this.entities.SaveChanges();

            return ret;
        }

        #region Encrypt
        // From http://khoinguonit.com/f81/ma-hoa-va-giai-ma-md5-trong-c-568/
        public string Encrypt(string toEncrypt, string key, bool useHashing)
        {
            byte[] keyArray;
            byte[] toEncryptArray = UTF8Encoding.UTF8.GetBytes(toEncrypt);

            if (useHashing)
            {
                MD5CryptoServiceProvider hashmd5 = new MD5CryptoServiceProvider();
                keyArray = hashmd5.ComputeHash(UTF8Encoding.UTF8.GetBytes(key));
            }
            else
                keyArray = UTF8Encoding.UTF8.GetBytes(key);

            TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider();
            tdes.Key = keyArray;
            tdes.Mode = CipherMode.ECB;
            tdes.Padding = PaddingMode.PKCS7;

            ICryptoTransform cTransform = tdes.CreateEncryptor();
            byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);

            return Convert.ToBase64String(resultArray, 0, resultArray.Length);
        }

        public static string Decrypt(string toDecrypt, string key, bool useHashing)
        {
            byte[] keyArray;
            byte[] toEncryptArray = Convert.FromBase64String(toDecrypt);

            if (useHashing)
            {
                MD5CryptoServiceProvider hashmd5 = new MD5CryptoServiceProvider();
                keyArray = hashmd5.ComputeHash(UTF8Encoding.UTF8.GetBytes(key));
            }
            else
                keyArray = UTF8Encoding.UTF8.GetBytes(key);

            TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider();
            tdes.Key = keyArray;
            tdes.Mode = CipherMode.ECB;
            tdes.Padding = PaddingMode.PKCS7;

            ICryptoTransform cTransform = tdes.CreateDecryptor();
            byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);

            return UTF8Encoding.UTF8.GetString(resultArray);
        }
        #endregion

        private bool ValidEmailSyntax(string email)
        {
            bool ret = true;
            // Validate email here

            return ret;
        }
    }

    [Flags]
    public enum CreateUserStatus
    {
        Success = 0,
        DuplicateEmail = 1,
        EmailInvalid = 2
    }
}